package com.gitee.wsl.collections.list

import com.gitee.wsl.ext.collection.getByIndexOrNull

open class LinkedList<T>:MutableList<T> {

    data class Node<T>(var data: T, var next: Node<T>?)

    override var size = 0

    override fun addAll(elements: Collection<T>): Boolean {
        var currentNode=head
        while (currentNode!!.next !=null){
            currentNode=currentNode.next
        }
        for (i in elements){
            add(i)
            size++
        }
        return true
    }

    override fun addAll(index: Int, elements: Collection<T>): Boolean {
        var currentNode=head
        repeat(index){
            currentNode=currentNode!!.next
        }
        for (i in elements){
            println(i)
            currentNode!!.next= Node(i, currentNode.next)
            size++
        }
        return true
    }

    override fun add(index: Int, element: T) {
        var currentNode=head
        repeat(index){
            currentNode=currentNode!!.next
        }
        if(currentNode==null){
            println(-1)
        }else {
            currentNode.next = Node(element, currentNode.next)
            size++
        }
    }

    override fun containsAll(elements: Collection<T>): Boolean {
       return all { contains(it) }
    }

    override fun contains(element: T): Boolean {
       return getFirstIndex(element) != null
    }

    var head: Node<T>? = null

    fun printAll() {
        var currentNode = head
        if (currentNode == null) {
            println("Linkedlist is empty")
        } else {
            print("${currentNode!!.data} ")
            while (currentNode!!.next != null) {
                currentNode = currentNode.next
                print("${currentNode!!.data} ")
            }
        }
    }

    override fun isEmpty():Boolean{
        return size == 0
    }

    override fun iterator(): MutableIterator<T> {
        TODO("Not yet implemented")
    }

    override fun listIterator(): MutableListIterator<T> {
        TODO("Not yet implemented")
    }

    override fun listIterator(index: Int): MutableListIterator<T> {
        TODO("Not yet implemented")
    }

    override fun removeAll(elements: Collection<T>): Boolean {
        elements.forEach { remove(it) }
        return true
    }

    override fun subList(fromIndex: Int, toIndex: Int): MutableList<T> {
        return (fromIndex..toIndex).map { get(it) }.toMutableList()
    }

    override fun lastIndexOf(element: T): Int {
        return getLastIndex(element)?:-1
    }

    override fun add(element: T): Boolean {
        if (isEmpty()) {
            head = Node(element, null)
            size++
        } else {
            var currentNode = head
            while (currentNode!!.next != null) {
                currentNode = currentNode.next
            }
            currentNode.next =Node(element, null)
            size++
        }
        return true
    }

    override fun get(index: Int):T {
        var currentNode = head
        repeat(index) {
            currentNode = currentNode!!.next
        }
        return currentNode!!.data!!
    }

    override fun indexOf(element: T): Int {
       return getFirstIndex(element)?:-1
    }


    fun replaceAll(old:T,data: T){
        var currentNode=head
        var t=0
        if (currentNode!!.data==old) {
            currentNode.data=data
        }
        while (currentNode!!.next !=null){
            currentNode = currentNode.next
            if (currentNode!!.data==old){
                currentNode.data=data
                t++
            }

        }
        if (t==0){
            println(-1)
        }
    }


    override fun removeAt(index: Int): T {
        var removeItem:T? = null
        if (index == 0){
            removeItem = head!!.data
            head = head!!.next
            --size
        }else{
            var currentNode = head
            for(i in 1 until index){
                currentNode = currentNode!!.next
            }
            if(currentNode == null){
                println(-1)
            }else{
                removeItem = currentNode.next!!.data
                currentNode.next = currentNode.next!!.next
                --size
            }
        }
        return removeItem?:throw IndexOutOfBoundsException()
    }

    override fun set(index: Int, element: T): T {
        if(index < 0 || index >= size){
            throw IndexOutOfBoundsException()
        }
        var currentNode = head
        repeat(index) {
            currentNode = currentNode!!.next
        }
        require(currentNode != null){"index out of bounds"}
        currentNode.data = element
        return currentNode.data
    }

    override fun retainAll(elements: Collection<T>): Boolean {
        val copy = this.toMutableList()
        val ret = copy.retainAll(elements)
        if(ret) {
            this.clear()
            this.addAll(copy)
        }
        return ret
    }

    override fun remove(element:T):Boolean{
        var currentNode=head
        var check=0
        val beforeSize = size
        if (currentNode!!.data==element){
            head=head!!.next
            --size
            currentNode=head
        }
        for (i in 1 until size){
            if (currentNode!!.next?.data == element){
                currentNode.next=currentNode.next?.next
                check++
                --size
            }else{
                currentNode=currentNode.next
            }

        }
        if (check==0){
            println( "data in not available")
        }
        return beforeSize != size
    }

    fun getFirstIndex(data:T):Int?{
        var check:Int?=null
        var currentNode=head

        for(i in 0 until size){
            if (currentNode!!.data==data){
                check=i
                break
            }
            currentNode=currentNode.next
        }
        return check
    }

    fun getLastIndex(data:T):Int?{
        var check:Int?=null
        var currentNode=head

        for(i in 0 until size){
            if (currentNode!!.data==data){
                check=i
            }
            currentNode=currentNode.next
        }
        return check
    }

    fun getIndices0f(data:T):List<Int>{
        val list =ArrayList<Int>()
        var currentNode=head
        var check=0
        for(i in 0 until size){
            if(currentNode!!.data==data){
                list.add(i)
                ++check
            }
            currentNode= currentNode.next
        }
        if (check==0){
            return emptyList()
        }
        return list
    }

    override fun clear(){
        head = null
        size = 0
    }

    fun removeFirstOrNull(): T? {
       val first = getByIndexOrNull(0)?:return null
       removeAt(0)
       return first
    }

}